﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace RemoteDesktopLib
{
    //Enum chứa các loại command
    public enum CommandTypeOption 
    {
        MouseMove,
        MouseDown,
        MouseUp,
        MouseDoubleClick,
        MouseWheel,
        KeyDown,
        KeyUp,
        None
    };

     public enum MouseButtons
     {
        Left = 0x2,
        Right = 0x8,
        Middle = 0x20,
        None = 0x100,
     };

    public class CommandInfo
    {
        // Properties loại command
        public CommandTypeOption CommandType { get; set; }

        // Dữ liệu truyền vào theo command
        public string Data { get; set; }

        public CommandInfo(CommandTypeOption commandType, string data)
        {
            CommandType = commandType;
            Data = data;
        }

        public static CommandTypeOption GetCommandType(int hookType)
        {
            switch(hookType)
            {
                case Win32Stuff.WM_MOUSEMOVE:
                    return CommandTypeOption.MouseMove;
                case Win32Stuff.WM_LBUTTONDOWN:
                case Win32Stuff.WM_RBUTTONDOWN:
                case Win32Stuff.WM_MBUTTONDOWN:
                    return CommandTypeOption.MouseDown;
                case Win32Stuff.WM_LBUTTONUP:
                case Win32Stuff.WM_RBUTTONUP:
                case Win32Stuff.WM_MBUTTONUP:
                    return CommandTypeOption.MouseUp;
                case Win32Stuff.WM_LBUTTONDBLCLK:
                case Win32Stuff.WM_RBUTTONDBLCLK:
                case Win32Stuff.WM_MBUTTONDBLCLK:
                    return CommandTypeOption.MouseDoubleClick;
                case Win32Stuff.WM_MOUSEWHEEL:
                    return CommandTypeOption.MouseWheel;
                case Win32Stuff.WM_KEYDOWN:
                case Win32Stuff.WM_SYSKEYDOWN:
                    return CommandTypeOption.KeyDown;
                case Win32Stuff.WM_KEYUP:
                case Win32Stuff.WM_SYSKEYUP:
                    return CommandTypeOption.KeyUp;
                default:
                    return CommandTypeOption.None;
            }
        }
        
        public static MouseButtons GetMouseButton(int mouseHookType)
        {
            switch(mouseHookType)
            {
                case Win32Stuff.WM_LBUTTONDOWN:
                case Win32Stuff.WM_LBUTTONUP:
                case Win32Stuff.WM_LBUTTONDBLCLK:
                    return MouseButtons.Left;
                case Win32Stuff.WM_RBUTTONDOWN:
                case Win32Stuff.WM_RBUTTONUP:
                case Win32Stuff.WM_RBUTTONDBLCLK:
                    return MouseButtons.Right;
                case Win32Stuff.WM_MBUTTONDOWN:
                case Win32Stuff.WM_MBUTTONUP:
                case Win32Stuff.WM_MBUTTONDBLCLK:
                    return MouseButtons.Middle;
                default:
                    return MouseButtons.None;
            }
        }

        public static CommandInfo Parse(string input)
        {
            string[] parts = input.Split('|');
            if (parts.Length != 2)
            {
                return null;
            }
            CommandTypeOption type = (CommandTypeOption)Enum.Parse(typeof(CommandTypeOption), parts[0]);
            string data = parts[1];
            return new CommandInfo(type, data);
        }
    }

    public static class Command
    {

        // Hằng xác định các sự kiện mouse sử dụng trong mouse_event.
        const int MOUSEEVENTF_MOVE = 0x1;
        const int MOUSEEVENTF_LEFTDOWN = 0x2;
        const int MOUSEEVENTF_LEFTUP = 0x4;
        const int MOUSEEVENTF_RIGHTDOWN = 0x8;
        const int MOUSEEVENTF_RIGHTUP = 0x10;
        const int MOUSEEVENTF_MIDDLEDOWN = 0x20;
        const int MOUSEEVENTF_MIDDLEUP = 0x40;
        const int MOUSEEVENTF_WHEEL = 0x800;
        const int MOUSEEVENTF_ABSOLUTE = 0x8000;

        //  Hằng xác định các sự kiện keyboard sử dụng trong keybd_event.
        const int KEYEVENTF_EXTENDEDKEY = 0x1;
        const int KEYEVENTF_KEYUP = 0x2;

        public static void Execute(CommandInfo cmd)
        {
            switch (cmd.CommandType)
            {
                case CommandTypeOption.MouseMove:
                    MouseMove(cmd.Data);
                    break;
                case CommandTypeOption.MouseDown:
                    MouseDown(cmd.Data);
                    break;
                case CommandTypeOption.MouseUp:
                    MouseUp(cmd.Data);
                    break;
                case CommandTypeOption.MouseDoubleClick:
                    MouseDoubleClick(cmd.Data);
                    break;
                case CommandTypeOption.MouseWheel:
                    MouseWheel(cmd.Data);
                    break;
                case CommandTypeOption.KeyDown:
                    KeyDown(cmd.Data);
                    break;
                case CommandTypeOption.KeyUp:
                    KeyUp(cmd.Data);
                    break;
                case CommandTypeOption.None:
                    break;
                default:
                    break;
            }     
        }

        private static void MouseMove(string data)
        {
            string[] parts = data.Split(',');
            if (parts.Length != 2)
            {
                return;
            }
            int cursorX = int.Parse(parts[0]);
            int cursorY = int.Parse(parts[1]);

            Cursor.Position = new System.Drawing.Point(cursorX, cursorY);
        }

        private static void MouseDown(string data)
        {
            MouseButtons button = (MouseButtons)Enum.Parse(typeof(MouseButtons), data);

            if (button == MouseButtons.None)
                return;

            Win32Stuff.mouse_event((int)button, 0, 0, 0, 0);
        }

        private static void MouseUp(string data)
        {
            MouseButtons button = (MouseButtons)Enum.Parse(typeof(MouseButtons), data);

            if (button == MouseButtons.None)
                return;

            Win32Stuff.mouse_event((int)button * 2, 0, 0, 0, 0);
        }

        private static void MouseClick(MouseButtons button)
        {
            // Mouse Down of button.
            Win32Stuff.mouse_event((int)button, 0, 0, 0, 0);
            // Mouse Up of button.
            Win32Stuff.mouse_event((int)button * 2, 0, 0, 0, 0);
        }

        private static void MouseDoubleClick(string data)
        {
            MouseButtons button = (MouseButtons)Enum.Parse(typeof(MouseButtons), data);

            if (button == MouseButtons.None)
                return;

            MouseClick(button);
            MouseClick(button);
        }

        private static void MouseWheel(string data)
        {
            int delta = int.Parse(data);

            Win32Stuff.mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0);
        }

        private static byte ParseKey(Keys key)
        {

            // Alt, Shift, and Control need to be changed for API function to work with them
            switch (key)
            {
                case Keys.Alt:
                    return (byte)18;
                case Keys.Control:
                    return (byte)17;
                case Keys.Shift:
                    return (byte)16;
                default:
                    return (byte)key;
            }

        } 

        private static void KeyDown(string data)
        {
            Keys key = (Keys)Enum.Parse(typeof(Keys), data);

            Win32Stuff.keybd_event((byte)key, 0, 0, 0);
        }

        private static void KeyUp(string data)
        {
            Keys key = (Keys)Enum.Parse(typeof(Keys), data);

            Win32Stuff.keybd_event((byte)key, 0, KEYEVENTF_KEYUP, 0);
        }

    }
}
